const BOSS_MODEL = [
//蓝色身体
  {
    points: [

      [7, -5],
      [7, 5],
      [-7, 5],
      [-7, -5],
      [7, -5]

    ],
    height: 10.0,
    base_height: 0.0,
    color: '#69ccf3'
  },
//蓝色脸
  {
    points: [

      [6, -7],
      [6, -5],
      [-6, -5],
      [-6, -7],
      [6, -7]

    ],
    height: 8.0,
    base_height: 2.0,
    color: '#69ccf3'
  },

//黑色眼睛左
  {
    points: [

      [-1, -7.5],
      [-1, -7],
      [-2, -7],
      [-2, -7.5],
      [-1, -7.5]

    ],
    height: 8.0,
    base_height: 4.0,
    color: '#2a2a2c'
  },
  //黑色眼睛右
  {
    points: [

      [2, -7.5],
      [2, -7],
      [1, -7],
      [1, -7.5],
      [2, -7.5]

    ],
    height: 8.0,
    base_height: 4.0,
    color: '#2a2a2c'
  },


//左耳朵
  {
    points: [

      [-1, -1],
      [-1, 2],
      [-4, 2],
      [-4, -1],
      [-1, -1]
    ],
    height: 15,
    base_height: 10.0,
    color: '#2a2a2c'
  },
  {
    points: [

      [-1, 2],
      [-1, 5],
      [-4, 5],
      [-4, 2],
      [-1, 2]
    ],
    height: 16,
    base_height: 13.0,
    color: '#2a2a2c'
  },

//右耳朵

  {
    points: [

      [5, -1],
      [5, 2],
      [2, 2],
      [2, -1],
      [5, -1]
    ],
    height: 15,
    base_height: 10.0,
    color: '#2a2a2c'
  },
  {
    points: [

      [5, 2],
      [5, 5],
      [2, 5],
      [2, 2],
      [5, 2]
    ],
    height: 16,
    base_height: 13.0,
    color: '#2a2a2c'
  },


];
const BOSS_MODEL_2 = [
//蓝色身体
  {
    points: [

      [7, -5],
      [7, 5],
      [-7, 5],
      [-7, -5],
      [7, -5]

    ],
    height: 10.0,
    base_height: 0.0,
    color: '#6a81f6'
  },
//蓝色脸
  {
    points: [

      [6, -7],
      [6, -5],
      [-6, -5],
      [-6, -7],
      [6, -7]

    ],
    height: 8.0,
    base_height: 2.0,
    color: '#6a81f6'
  },

//黑色眼睛左横着
  {
    points: [

      [-1, -7.5],
      [-1, -7],
      [-4, -7],
      [-4, -7.5],
      [-1, -7.5]

    ],
    height: 6.0,
    base_height: 4.0,
    color: '#2a2a2c'
  },
  //黑色眼睛右横着
  {
    points: [

      [5, -7.5],
      [5, -7],
      [2, -7],
      [2, -7.5],
      [5, -7.5]

    ],
    height: 6.0,
    base_height: 4.0,
    color: '#2a2a2c'
  },


//左耳朵
  {
    points: [

      [-1, -1],
      [-1, 2],
      [-4, 2],
      [-4, -1],
      [-1, -1]
    ],
    height: 15,
    base_height: 10.0,
    color: '#2a2a2c'
  },
  {
    points: [

      [-1, 2],
      [-1, 5],
      [-4, 5],
      [-4, 2],
      [-1, 2]
    ],
    height: 16,
    base_height: 13.0,
    color: '#2a2a2c'
  },

//右耳朵

  {
    points: [

      [5, -1],
      [5, 2],
      [2, 2],
      [2, -1],
      [5, -1]
    ],
    height: 15,
    base_height: 10.0,
    color: '#2a2a2c'
  },
  {
    points: [

      [5, 2],
      [5, 5],
      [2, 5],
      [2, 2],
      [5, 2]
    ],
    height: 16,
    base_height: 13.0,
    color: '#2a2a2c'
  },


]

const CIIC = [
  {x: 116.496986, y: 39.928223, name: '国安社区 东风店'},
  {x: 116.55854, y: 39.960385, name: '国安社区 东坝店'},
  {x: 116.321465, y: 39.884632, name: '国安社区 太平桥店'},
  {x: 116.372002, y: 39.8484, name: '国安社区 未来方舟店'},
  {x: 116.396461, y: 39.934231, name: '国安社区品质生活体验中心 什刹海店'},
  {x: 119.74995, y: 41.130383, name: '国安社区 管庄店'},
  {x: 116.197701, y: 39.923317, name: '国安社区 八角店'},
  {x: 102.704788, y: 25.052841, name: '国安社区 华山月店'},
  {x: 102.697801, y: 24.996846, name: '国安社区 前卫月店'},
  {x: 116.460373, y: 39.922085, name: '国安社区 呼家楼店'},
  {x: 102.737149, y: 25.021119, name: '国安社区 吴井月店'},
  {x: 120.833408, y: 32.036507, name: '国安社区 通州北苑店'},
  {x: 116.371826, y: 40.032967, name: '国安社区 东升店'},
  {x: 116.505524, y: 39.866997, name: '国安社区 垡头店'},
  {x: 116.44622, y: 39.963852, name: '国安社区 香河园店'},
  {x: 116.692513, y: 39.915359, name: '国安社区 潞城店'},
  {x: 116.3362, y: 40.035795, name: '国安社区 清河店'},
  {x: 116.371048, y: 39.840599, name: '国安社区 马家堡店'},
  {x: 106.653656, y: 26.61314, name: '国安社区 高新旗舰店'},
  {x: 116.429047, y: 40.003151, name: '国安社区 大屯星店（嘉铭园店）'},
  {x: 116.431953, y: 39.860817, name: '国安社区 方庄店'},
  {x: 113.244644, y: 23.126974, name: '国安社区 逢源店'},
  {x: 116.522491, y: 39.916094, name: '国安社区 兴隆家园店'},
  {x: 116.329813, y: 39.773363, name: '国安社区 高米店店'},
  {x: 116.424413, y: 39.885867, name: '国安社区 体育馆路店'},
  {x: 116.3596, y: 39.845519, name: '国安社区 新村店'},
  {x: 116.444283, y: 39.920628, name: '国安社区 朝外店'},
  {x: 116.349129, y: 39.729523, name: '国安社区 观音寺店'},
  {x: 116.277344, y: 39.929043, name: '国安社区 西八里庄月店'},
  {x: 113.91947, y: 22.527548, name: '国安社区 锦福店'},
  {x: 116.293381, y: 39.967422, name: '国安社区 万柳店'},
  {x: 116.409051, y: 39.969555, name: '国安社区 和平街店'},
  {x: 116.318944, y: 39.844883, name: '国安社区 首经贸校园店'},
  {x: 116.29631, y: 39.884579, name: '国安社区 六里桥店'},
  {x: 113.928389, y: 22.515909, name: '国安社区 粤海店'},
  {x: 116.336917, y: 39.930006, name: '国安社区 百万庄星店'},
  {x: 121.676708, y: 42.004503, name: '国安社区 太平街星店'},
  {x: 116.459236, y: 39.905624, name: '国安社区 双井店'},
  {x: 116.385597, y: 39.966358, name: '国安社区 德胜店'},
  {x: 117.013023, y: 32.631512, name: '国安社区 北京师范大学店'},
  {x: 116.37835, y: 39.971242, name: '国安社区 花园路店'},
  {x: 116.41675, y: 39.78647, name: '国安社区 旧宫星店'},
  {x: 116.42614, y: 39.897606, name: '国安社区 崇文门外店'},
  {x: 116.436444, y: 39.89744, name: '国安社区 东花市店'},
  {x: 116.425972, y: 39.943058, name: '国安社区 北新桥店'},
  {x: 116.356476, y: 39.79287, name: '国安社区 西红门星店'},
  {x: 113.241463, y: 23.121069, name: '国安社区 陈家祠店'},
  {x: 116.27169, y: 39.954308, name: '国安社区 四季青店'},
  {x: 116.640709, y: 39.874592, name: '国安社区 梨园店'},
  {x: 125.288319, y: 43.833513, name: '国安社区 三里屯店'},
  {x: 116.477577, y: 40.003056, name: '国安社区 东湖店'},
  {x: 116.326829, y: 39.892864, name: '国安社区 广安门外一店'},
  {x: 116.514832, y: 39.934803, name: '国安社区 平房店'},
  {x: 102.740239, y: 25.072795, name: '国安社区 金辰星店'},
  {x: 116.309407, y: 39.988657, name: '国安社区 北京大学店'},
  {x: 116.415633, y: 40.057691, name: '国安社区 天通苑南店'},
  {x: 116.448912, y: 39.843623, name: '国安社区 东铁匠营店'},
  {x: 116.491463, y: 39.965698, name: '国安社区 酒仙桥店'},
  {x: 116.457161, y: 39.919403, name: '国安社区 呼家楼万通星店'},
  {x: 116.369217, y: 39.918083, name: '国安社区 金融街店'},
  {x: 116.312744, y: 39.939655, name: '国安社区品质生活体验中心 紫竹院星店'},
  {x: 116.348816, y: 40.007095, name: '国安社区 林业大学店'},
  {x: 125.288319, y: 43.833513, name: '国安社区 望京店'},
  {x: 116.333443, y: 39.989357, name: '国安社区 中关村店'},
  {x: 116.599838, y: 39.929008, name: '国安社区 常营店'},
  {x: 120.562098, y: 31.292023, name: '国安社区 海淀店'},
  {x: 113.320367, y: 33.71205, name: '国安社区 中仓店'},
  {x: 116.313103, y: 39.745327, name: '国安社区 清源店'},
  {x: 116.455403, y: 39.950636, name: '国安社区 左家庄店'},
  {x: 114.410622, y: 23.118273, name: '国安社区 中天花园店'},
  {x: 116.302731, y: 39.891993, name: '国安社区 羊坊店'},
  {x: 116.364627, y: 39.871821, name: '国安社区 白纸坊店'},
  {x: 116.472939, y: 39.861866, name: '国安社区 十八里店'},
  {x: 116.361002, y: 39.929847, name: '国安社区 新街口店店'},
  {x: 116.455128, y: 39.799772, name: '国安社区 旧宫店'},
  {x: 116.503944, y: 39.896324, name: '国安社区 百子湾星店'},
  {x: 116.339302, y: 39.927043, name: '国安社区 展览路店'},
  {x: 111.474464, y: 33.131573, name: '国安社区 永定门店'},
  {x: 116.378662, y: 39.891857, name: '国安社区椿树店'},
  {x: 121.075087, y: 32.064161, name: '国安社区 通州北苑二店'},
  {x: 116.387428, y: 39.863865, name: '国安社区 西罗园店'},
  {x: 116.354748, y: 39.89234, name: '国安社区 广安门内店'},
  {x: 116.434784, y: 40.064926, name: '国安社区 天通苑北店'},
  {x: 106.644839, y: 26.637214, name: '国安社区 会展城店'},
  {x: 116.410484, y: 39.928013, name: '国安社区 景山店'},
  {x: 106.619986, y: 26.663421, name: '国安社区 新世界店'},
  {x: 116.280962, y: 39.965769, name: '国安社区 曙光店'},
  {x: 116.309387, y: 40.037338, name: '国安社区 上地店'},
  {x: 116.372414, y: 40.009151, name: '国安社区 奥运村店'},
  {x: 116.442898, y: 39.936583, name: '国安社区 东直门店'},
  {x: 116.211555, y: 39.900337, name: '国安社区 鲁谷店'},
  {x: 116.426232, y: 39.929184, name: '国安社区 东四店'},
  {x: 116.345734, y: 39.960182, name: '国安社区 中央财经大学店'},
  {x: 102.739266, y: 25.083761, name: '国安社区 金辰月店'},
  {x: 116.347626, y: 39.905136, name: '国安社区 月坛店'},
  {x: 116.384537, y: 39.883945, name: '国安社区 陶然亭店'},
  {x: 102.718343, y: 25.071028, name: '国安社区 联盟月店'},

  {x: 116.414703, y: 40.09293, name: '国安社区 亚运村店'},

  {x: 116.409401, y: 40.04805, name: '国安社区 来广营店'},
  {x: 116.387901, y: 39.966103, name: '国安社区 德胜星店'},
  {x: 116.451515, y: 39.870693, name: '国安社区 潘家园店'},
  {x: 102.793839, y: 24.979367, name: '国安社区小板桥月店'},
  {x: 116.357949, y: 39.95822, name: '国安社区 北京邮电大学店'},
  {x: 116.45916, y: 39.966019, name: '国安社区 太阳宫店'},

  {x: 102.694387, y: 25.029227, name: '国安社区 金碧月店'},
  {x: 116.699478, y: 39.875183, name: '国安社区 玉桥店'},

  {x: 116.278038, y: 39.914639, name: '国安社区 万寿路店'},
  {x: 116.354362, y: 39.957134, name: '国安社区 北太平庄店'},
  {x: 116.163841, y: 39.929558, name: '国安社区 金顶街店'},
  {x: 116.34391, y: 39.948921, name: '国安社区 交通大学店'},
  {x: 116.427643, y: 39.919899, name: '国安社区 朝内店'},

  {x: 116.460373, y: 39.922085, name: '国安社区 国安宾馆'},
  {x: 116.373222, y: 39.925537, name: '国安社区 西四星店'},
  {x: 113.791975, y: 23.021756, name: '东莞麦当劳星河传说得来速'},
  {x: 118.588633, y: 24.904275, name: '泉州麦当劳中山餐厅'},
  {x: 121.140296, y: 28.856139, name: '临海麦当劳银泰城餐厅'},
  {x: 114.306778, y: 30.652372, name: '武汉麦当劳汉口城市广场餐厅'},
  {x: 118.312401, y: 32.304138, name: '滁州麦当劳苏宁广场餐厅'},
  {x: 120.692341, y: 30.498607, name: '海宁麦当劳银泰城餐厅'},
  {x: 116.476968, y: 39.885112, name: '北京麦当劳平乐园餐厅'},
  {x: 117.017732, y: 32.64097, name: '淮南麦当劳龙湖路餐厅'},
  {x: 119.929878, y: 31.643923, name: '成都麦当劳新世纪环球中心餐厅'},
  {x: 116.302153, y: 39.889539, name: '北京麦当劳莲宝路餐厅'},
  {x: 113.253989, y: 22.838168, name: '佛山麦当劳大良盈建分店'},
  {x: 113.553933, y: 23.112744, name: '广州麦当劳广深大道新墩得来速分店'},
  {x: 119.32603, y: 26.140181, name: '福州麦当劳坂中路餐厅'},
  {x: 126.663309, y: 45.754456, name: '哈尔滨麦当劳建设街餐厅'},
  {x: 115.800072, y: 33.870056, name: '亳州麦当劳人民路餐厅'},
  {x: 113.529875, y: 22.256963, name: '珠海麦当劳翠前北路餐厅'},
  {x: 116.368474, y: 39.832397, name: '北京麦当劳马家堡餐厅'},
  {x: 114.300936, y: 30.55058, name: '武汉麦当劳解放路餐厅'},
  {x: 114.238233, y: 22.558295, name: '深圳麦当劳海山路餐厅'},
  {x: 110.213389, y: 25.249246, name: '桂林麦当劳临桂金水路餐厅'},
  {x: 112.99379, y: 28.070465, name: '长沙麦当劳友阿奥特莱斯餐厅'},
  {x: 104.021489, y: 30.658724, name: '成都麦当劳光华餐厅'},
  {x: 113.300834, y: 22.96585, name: '广州麦当劳番禹兴业路分店'},
  {x: 122.977229, y: 39.699448, name: '大连麦当劳庄河延安路餐厅'},
  {x: 120.180304, y: 30.264646, name: '杭州麦当劳黄龙餐厅'},
  {x: 118.456502, y: 39.715596, name: '唐山麦当劳新林道餐厅'},
  {x: 117.163261, y: 39.158447, name: '天津麦当劳天津西站二餐厅'},
  {x: 118.176724, y: 24.504924, name: '厦门麦当劳仙岳路餐厅'},
  {x: 114.064923, y: 22.520311, name: '深圳麦当劳金田分店'},
  {x: 125.288319, y: 43.833513, name: '北京麦当劳东大桥餐厅'},
  {x: 120.951395, y: 31.403094, name: '昆山麦当劳北门路餐厅'},
  {x: 118.826952, y: 25.136578, name: '泉州麦当劳驿坂高速公路服务区B区餐厅'},
  {x: 113.20212, y: 23.140796, name: '佛山麦当劳黄岐建设大道分店'},
  {x: 114.308147, y: 22.594617, name: '深圳麦当劳大梅沙分店'},
  {x: 115.98972, y: 29.725893, name: '九江麦当劳九江火车站餐厅'},
  {x: 113.011208, y: 22.970584, name: '佛山麦当劳南庄吉利得来速'},
  {x: 104.250457, y: 23.368434, name: '文山麦当劳东风路光大广场餐厅'},
  {x: 123.508649, y: 41.746395, name: '沈阳麦当劳浑南中石化得来速'},
  {x: 120.37172, y: 31.486147, name: '无锡麦当劳震泽路FSDT餐厅'},
  {x: 120.171866, y: 30.325772, name: '杭州麦当劳城北银泰餐厅'},
  {x: 125.300111, y: 43.87125, name: '长春麦当劳红旗街分店'},
  {x: 121.511921, y: 31.260328, name: '上海麦当劳宝地广场餐厅'},
  {x: 117.027839, y: 28.23545, name: '鹰潭麦当劳鹰潭火车站餐厅'},
  {x: 113.97089, y: 23.014871, name: '东莞麦当劳横沥分店'},
  {x: 110.483989, y: 29.105669, name: '张家界麦当劳长途客运站餐厅'},
  {x: 114.396923, y: 23.081609, name: '惠州麦当劳鹅岭北路餐厅'},
  {x: 108.372957, y: 22.81207, name: '南宁麦当劳汇东国际分店'},
  {x: 120.354513, y: 36.101033, name: '青岛麦当劳汽车总站餐厅'},
  {x: 113.300685, y: 40.088425, name: '大同麦当劳教场街餐厅'},
  {x: 116.191723, y: 39.906902, name: '北京麦当劳古城餐厅'}
];

$(function() {
  mapboxgl.accessToken = 'pk.eyJ1IjoibGNmdGMiLCJhIjoiY2phZXMyN2NyMHdvYTJxcGxpM2w1dGdoMiJ9.hEs9r9Kykiyqr8Bf8kiD_w';

  let C_LNG = -74.0066;
  let C_LAT = 40.7135;
  let FACTOR = 0.00001;
  let PI = 3.141592653;
  let LEVEL = 0;
  let iEvent = 0;
  const aBosses = [];
  const aUsers = [];


  const map = new mapboxgl.Map({
    style: 'mapbox://styles/mapbox/light-v9',
    //center: [C_LNG, C_LAT],
    center: [CIIC[0].x, CIIC[0].y],
    zoom: 5,
    pitch: 45,
    bearing: -17.6,
    hash: true,
    container: 'map'
  });

  function convert(aModel, position) {
    const MUL = 8;

    return {
      "type": "geojson",
      "data": {
        "type": "FeatureCollection",
        "features": aModel.map(d => {
          return {
            "type": "Feature",
            "properties": {
              "level": 1000,
              "height": d.height * MUL,
              "base_height": d.base_height * MUL,
              "color": d.color
            },
            "geometry": {
              "coordinates": [
                d.points.map(p => {
                  return [position[0] + p[0] * MUL * FACTOR, position[1] + p[1] * MUL * FACTOR]
                })
              ],
              "type": "Polygon"
            }
          }
        })
      }
    };
  }

  // function get_x(rem) {
  //   return C_LNG + rem * FACTOR;
  // }
  //
  // function get_y(rem) {
  //   return C_LAT + rem * FACTOR;
  // }

  function get_id() {
    return `${new Date().getTime()}-${Math.random()}`;
  }

  function get_circle(position, radius) {
    let res = [];
    for (let i = 0; i < 2 * PI; i += 0.1) {
      res.push([
        Math.cos(i) * radius * FACTOR + position[0],
        Math.sin(i) * radius * FACTOR + position[1]
      ])
    }
    return res;
  }

  function drawBoss(position, fnClick) {
    let sBossId = `boss_${get_id()}`;
    let circleId = `circle_${get_id()}`;

    map.addSource(sBossId, convert(BOSS_MODEL, position));


    map.addLayer({
      "id": sBossId,
      "source": sBossId,
      'type': 'fill-extrusion',
      "paint": {
        'fill-extrusion-color': {
          // Get the fill-extrusion-color from the source 'color' property.
          'property': 'color',
          'type': 'identity'
        },
        'fill-extrusion-height': {
          // Get fill-extrusion-height from the source 'height' property.
          'property': 'height',
          'type': 'identity'
        },
        'fill-extrusion-base': {
          // Get fill-extrusion-base from the source 'base_height' property.
          'property': 'base_height',
          'type': 'identity'
        },
        // Make extrusions slightly opaque for see through indoor walls.
        'fill-extrusion-opacity': 0.8
      }
    });

    map.addLayer({
      "id": circleId,
      "source": {
        "type": "geojson",
        "data": {
          "type": "FeatureCollection",
          "features": [{
            "type": "Feature",
            "properties": {
              "level": LEVEL++,
              "height": 0,
              "base_height": 0,
              "color": '#93FFBD'
            },
            "geometry": {
              "coordinates": [
                get_circle(position, 500)
              ],
              "type": "Polygon"
            }
          }]
        }
      },
      'type': 'fill-extrusion',
      "paint": {
        'fill-extrusion-color': {
          'property': 'color',
          'type': 'identity'
        },
        'fill-extrusion-opacity': 0.5
      }
    });

    if ($.isFunction(fnClick)) {
      map.on('click', sBossId, fnClick);
    }

    return [sBossId, circleId];
  }

  function moveObject(source, dest) {
    let sPointId = `point_${get_id()}`;
    let xDiff = source[0] - dest[0];
    let yDiff = source[1] - dest[1];
    let iCount = 0;
    let iMax = 100;

    let fAngle = -25 + Math.atan((dest[0] - source[0]) / (dest[1] - source[1])) * 180 / PI;

    if (source[1] > dest[1]) {
      fAngle += 180;
    }
    let point = {
      "type": "FeatureCollection",
      "features": [{
        "type": "Feature",
        "geometry": {
          "type": "Point",
          "coordinates": Object.assign([], source)
        }
      }]
    };

    map.addSource(sPointId, {
      "type": "geojson",
      "data": point
    });


    map.addLayer({
      "id": sPointId,
      "source": sPointId,
      "type": "symbol",
      "layout": {
        "icon-image": "rocket-15",
        "icon-rotate": fAngle
      },
      "paint": {
        'icon-color': 'red'
      }
    });

    return new Promise(resolve => {
      function animate() {
        iCount++;
        // Update point geometry to a new position based on counter denoting
        // the index to access the arc.
        point.features[0].geometry.coordinates[0] -= xDiff / iMax;
        point.features[0].geometry.coordinates[1] -= yDiff / iMax;
        //route.features[0].geometry.coordinates[counter];

        // Update the source with this new data.
        map.getSource(sPointId).setData(point);

        // Request the next frame of animation so long as destination has not
        // been reached.
        if (iCount < iMax) {
          requestAnimationFrame(animate);
        } else {
          map.removeLayer(sPointId);

          resolve();
        }
      }

      animate();
    });


  }

  function showLabelWithAnim(source, text) {
    let sLabelId = `label_${get_id()}`;
    let iCount = 0;
    let iMax = 35;
    let iHeight = -8;

    map.addLayer({
      "id": sLabelId,
      "type": "symbol",
      "source": {
        "type": "geojson",
        "data": {
          "type": "FeatureCollection",
          "features": [{
            "type": "Feature",
            "geometry": {
              "type": "Point",
              "coordinates": source
            },
            "properties": {
              "title": text
            }
          }]
        }
      },
      "layout": {
        "text-field": "{title}",
        "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
        "text-offset": [0, 0],
        "text-anchor": "top",
        "text-size": 30
      },
      "paint": {
        'text-color': 'red'
      }
    });

    return new Promise(resolve => {
      function animate() {
        iCount++;

        map.setLayoutProperty(sLabelId, 'text-offset', [0, iCount * iHeight / iMax])

        // Request the next frame of animation so long as destination has not
        // been reached.
        if (iCount < iMax) {
          requestAnimationFrame(animate);
        } else {
          map.removeLayer(sLabelId);
          resolve();
        }
      }

      animate();
    });
  }

  function showLabel(source, text) {
    let sLabelId = `labeltext_${get_id()}`;
    let iCount = 0;
    let iMax = 35;
    let iHeight = -8;

    map.addLayer({
      "id": sLabelId,
      "type": "symbol",
      "source": {
        "type": "geojson",
        "data": {
          "type": "FeatureCollection",
          "features": [{
            "type": "Feature",
            "geometry": {
              "type": "Point",
              "coordinates": source
            },
            "properties": {
              "title": text
            }
          }]
        }
      },
      "layout": {
        "text-field": "{title}",
        "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
        "text-offset": [0, 1],
        "text-anchor": "top",
        "text-size": 15
      },
      "paint": {
        'text-color': 'Black'
      }
    });

    return sLabelId;
  }

  function showPoint(source) {
    let sPointId = `point_${get_id()}`;

    map.addSource(sPointId, {
      "type": "geojson",
      "data": {
        "type": "Point",
        "coordinates": source
      }
    });

    map.addLayer({
      "id": sPointId,
      "source": sPointId,
      "type": "circle",
      "paint": {
        "circle-radius": 5,
        "circle-color": "#007cbf"
      }
    });

    return sPointId;
  }

  function showCIICPoints() {
    for (let p of CIIC) {
      p.PointId = showPoint([p.x, p.y]);
      p.LabelId = showLabel([p.x, p.y], p.name);
    }
  }

  function removeCIICPoints() {
    for (let p of CIIC) {
      if (p.LabelId) {
        map.removeLayer(p.LabelId);
        p.LabelId = null;
      }
      if (p.PointId) {
        map.removeLayer(p.PointId);
        p.PointId = null;
      }
    }
  }

  function BossObject(id, position, tall, iMaxLife) {
    let sLifebarId = null;
    let sLabelId = null;
    let iTotalLen = 100;
    let self = this;
    let iWidth = 10;
    let [sBossId, circleId] = drawBoss(position, function() {
      $("#dropList").fadeIn();
    });
    let mLabel = {
      1: "麦当劳 纽约旗舰店",
      2: "中信书店",
      3: "中信商城",
      4: "麦当劳"
    }

    this._id = id;
    this._iMaxLifeValue = iMaxLife;
    this._iCurLifeValue = iMaxLife;
    this._position = position;


    this.getPosition = function() {
      return this._position;
    }
    this.getId = function() {
      return this._id;
    }
    this.getMaxLifeValue = function() {
      return this._iMaxLifeValue;
    }
    this.getCurLifeValue = function() {
      return this._iCurLifeValue;
    }
    this.damageFromPlayer = function(oPlayer, iDamage) {
      return moveObject(oPlayer.getPosition(), this._position)
        .then(() => {
          //let iCur = self.updateLifeValue(self.getCurLifeValue() - iDamage);
          return showLabelWithAnim(this._position, `-${iDamage}`);
        });
    };
    this.remove = function() {
      map.removeLayer(sLifebarId);
      map.removeLayer(sBossId);
      map.removeLayer(circleId);
    };
    this.rebirth = function() {
      let a = drawBoss(position, function() {
        $("#dropList").fadeIn();
      });
      sLifebarId = this._drawLifeBar();
      sBossId = a[0];
      circleId = a[1];

      self.updateLifeValue(this._iMaxLifeValue);
    };

    function calcCoordinates(fPercent) {
      let remain = [
        [position[0] - 0.5 * iTotalLen * FACTOR, position[1] - 0.5 * iWidth * FACTOR],
        [position[0] - 0.5 * iTotalLen * FACTOR, position[1] + 0.5 * iWidth * FACTOR],
        [position[0] + (fPercent - 0.5) * iTotalLen * FACTOR, position[1] + 0.5 * iWidth * FACTOR],
        [position[0] + (fPercent - 0.5) * iTotalLen * FACTOR, position[1] - 0.5 * iWidth * FACTOR],
        [position[0] - 0.5 * iTotalLen * FACTOR, position[1] - 0.5 * iWidth * FACTOR]
      ];
      let lost = [
        [position[0] - (0.5 - fPercent) * iTotalLen * FACTOR, position[1] - 0.5 * iWidth * FACTOR],
        [position[0] - (0.5 - fPercent) * iTotalLen * FACTOR, position[1] + 0.5 * iWidth * FACTOR],
        [position[0] + 0.5 * iTotalLen * FACTOR, position[1] + 0.5 * iWidth * FACTOR],
        [position[0] + 0.5 * iTotalLen * FACTOR, position[1] - 0.5 * iWidth * FACTOR],
        [position[0] - (0.5 - fPercent) * iTotalLen * FACTOR, position[1] - 0.5 * iWidth * FACTOR]
      ];

      return [remain, lost];
    }


    //initialize
    let data = {
      "type": "FeatureCollection",
      "features": [
        {
          "type": "Feature",
          "properties": {
            "level": 1000,
            "height": (tall || 100) + iWidth,
            "base_height": (tall || 100),
            "color": 'Green'
          },
          "geometry": {
            "coordinates": [
              calcCoordinates(1)[0]
            ],
            "type": "Polygon"
          }
        },
        {
          "type": "Feature",
          "properties": {
            "level": 1000,
            "height": (tall || 100) + iWidth,
            "base_height": (tall || 100),
            "color": 'Red'
          },
          "geometry": {
            "coordinates": [
              calcCoordinates(1)[1]
            ],
            "type": "Polygon"
          }
        }
      ]
    };


    this._drawLifeBar = function() {
      let lifeId = `lifebar_${get_id()}`;

      map.addSource(lifeId, {
        "type": "geojson",
        "data": data
      });

      map.addLayer({
        "id": lifeId,
        "source": lifeId,
        'type': 'fill-extrusion',
        "paint": {
          'fill-extrusion-color': {
            // Get the fill-extrusion-color from the source 'color' property.
            'property': 'color',
            'type': 'identity'
          },
          'fill-extrusion-height': {
            // Get fill-extrusion-height from the source 'height' property.
            'property': 'height',
            'type': 'identity'
          },
          'fill-extrusion-base': {
            // Get fill-extrusion-base from the source 'base_height' property.
            'property': 'base_height',
            'type': 'identity'
          },
          // Make extrusions slightly opaque for see through indoor walls.
          'fill-extrusion-opacity': 0.8
        }
      });

      return lifeId;
    }

    sLabelId = showLabel(position, mLabel[this.getId()]);

    sLifebarId = this._drawLifeBar();

    this.updateLifeValue = function(value) {
      if (value < 0) {
        this._iCurLifeValue = 0;
      } else {
        this._iCurLifeValue = value;
      }

      let fPercent = this._iCurLifeValue / this._iMaxLifeValue;
      data.features[0].geometry.coordinates[0] = calcCoordinates(fPercent)[0];
      data.features[1].geometry.coordinates[0] = calcCoordinates(fPercent)[1];

      map.getSource(sLifebarId).setData(data);

      return this._iCurLifeValue;
    }

  }

  function PlayerObject(id, group_id, position) {
    this._position = position;
    this._id = id;
    this._groupId = -1;
    let self = this;
    let sImageId = `image_${get_id()}`;
    let sGroupImageId = `image_group_${get_id()}`;

    this.getId = function() {
      return this._id;
    };
    this.getPosition = function() {
      return this._position;
    };
    this.getGroupId = function() {
      return this._groupId;
    }

    this.setInGroup = function() {
      if (this.getId() !== aUsers[0].getId()) {
        aUsers[0].setInGroup();
      }

      if (this.getGroupId() !== 1) {
        this._groupId = 1;
        map.removeImage(sImageId);
        map.removeLayer(sImageId);

        map.loadImage(`img/user_${id}_group.png`, function(error, image) {
          map.addImage(sGroupImageId, image);
          map.addLayer({
            "id": sGroupImageId,
            "type": "symbol",
            "source": {
              "type": "geojson",
              "data": {
                "type": "FeatureCollection",
                "features": [{
                  "type": "Feature",
                  "geometry": {
                    "type": "Point",
                    "coordinates": position
                  }
                }]
              }
            },
            "layout": {
              "icon-image": sGroupImageId,
              "icon-size": 0.3
            }
          });

        });
      }
    };


    map.loadImage(`img/user_${id}.png`, function(error, image) {
      map.addImage(sImageId, image);
      map.addLayer({
        "id": sImageId,
        "type": "symbol",
        "source": {
          "type": "geojson",
          "data": {
            "type": "FeatureCollection",
            "features": [{
              "type": "Feature",
              "geometry": {
                "type": "Point",
                "coordinates": position
              }
            }]
          }
        },
        "layout": {
          "icon-image": sImageId,
          "icon-size": 0.3
        }
      });
    });

    map.on('click', sImageId, function() {
      if (self.getId() !== 1) {
        confirm("邀请加入你的团队?");
      }
    });
  }

  map.on('load', function() {
    // Insert the layer beneath any symbol layer.
    let layers = map.getStyle().layers;

    let labelLayerId;
    for (let i = 0; i < layers.length; i++) {
      if (layers[i].type === 'symbol' && layers[i].layout['text-field']) {
        labelLayerId = layers[i].id;
        break;
      }
    }

    map.addLayer({
      'id': '3d-buildings',
      'source': 'composite',
      'source-layer': 'building',
      'filter': ['==', 'extrude', 'true'],
      'type': 'fill-extrusion',
      'minzoom': 15,
      'paint': {
        'fill-extrusion-color': '#aaa',
        'fill-extrusion-height': [
          "interpolate", ["linear"], ["zoom"],
          15, 0,
          15.05, ["get", "height"]
        ],
        'fill-extrusion-base': [
          "interpolate", ["linear"], ["zoom"],
          15, 0,
          15.05,
          ["get", "min_height"]
        ],
        'fill-extrusion-opacity': 0.6
      }
    }, labelLayerId);


    showCIICPoints();

    function getUserObjById(id) {
      for (let u of aUsers) {
        if (u.getId() === id) {
          return u;
        }
      }
      return null;
    }


    function refreshBattle() {
      window.hackthon.getBattles(aBosses[0].getId(), iEvent + 1).then(d => {
        console.log(d);
        let i = -1;
        let aRequest = [];
        let bDied = false;

        for (let battle of d) {
          iEvent = battle.id;
          i++;

          if (battle.is_reborn) {
            setTimeout(() => {
              aBosses[0].rebirth();
              bDied = false;
            }, i * 400);
          } else {
            aRequest.push(new Promise(resolve => {
              setTimeout(() => {
                aBosses[0].damageFromPlayer(getUserObjById(battle.user.id), battle.damage)
                  .then(() => {
                    aBosses[0].updateLifeValue(battle.b.cur_health);
                    resolve();
                  });
              }, i * 400);
            }));


            if (!battle.b.live && bDied === false) {
              bDied = true;

              Promise.all(aRequest)
                .then(() => {
                  aBosses[0].remove();

                  setTimeout(() => {
                    $("#resultList").fadeIn();
                  }, 1000);

                });
            }
          }
        }
      });
    }

    function refreshUser() {
      window.hackthon.getUsers().then(d => {
        console.log(d);

        for (let user of d) {
          let oUser = getUserObjById(user.id);

          if (user.group_id > 0 && oUser.getGroupId() !== user.group_id) {
            console.log(user.group_id);
            oUser.setInGroup();

          }
        }

      });
    }

    $("#btnAttach").on('touchstart', function(event) {
      if ($(event.currentTarget).hasClass('cd')) {
        return;
      }


      window.hackthon.attack(aBosses[0].getId(), aUsers[0].getId())
        .then(() => {
          $(event.currentTarget).addClass('cd');

          let iCount = 0;
          let iCD = 30;

          function refresh() {
            iCount++;
            if (iCount >= iCD) {
              $(event.currentTarget).removeClass('cd').text("");
              clearInterval(iCdTicket);
            } else {
              $(event.currentTarget).text(Math.ceil((iCD - iCount - 10) / 10) + "." + ((iCD - iCount) % 10));
            }
          }

          refresh();

          let iCdTicket = setInterval(() => {
            refresh();
          }, 100);
        });
    });

    $("#btnFriends").on('touchstart', function() {
      $("#friendsPanel").animate({
        top: "50%"
      }, 700);
    });

    $("#btnCloseFriends").on('touchstart', function() {
      $("#friendsPanel").animate({
        top: "100%"
      }, 700);
    });

    $(".dialog").on('touchstart', function(event) {
      $(event.currentTarget).fadeOut();
    });

    $(".tab-item").on('touchstart', function(event) {
      $(".tab-item").removeClass('active');
      $(event.currentTarget).addClass('active');
    });

    $("#tabWallet").on('touchstart', function() {
      $("#frameWallet").show();
    });
    $("#tabGame").on('touchstart', function() {
      $("#frameWallet").hide();
    });

    $("#frameWallet>img").on('touchstart', function() {
      $("#qrcodeList").fadeIn();
    });

    $("#tabFriends").on('touchstart', function() {
      removeCIICPoints();

      map.flyTo({
        // These options control the ending camera position: centered at
        // the target, at zoom level 9, and north up.
        center: aBosses[0].getPosition(),
        zoom: 16,
        bearing: 0,

        // These options control the flight curve, making it move
        // slowly and zoom out almost completely before starting
        // to pan.
        speed: 0.7, // make the flying slow
        curve: 1, // change the speed at which it zooms out

        // This can be any easing function: it takes a number between
        // 0 and 1 and returns another number between 0 and 1.
        easing: function(t) {
          return t;
        }
      });
    });
    $("#tabMe").on('touchstart', function() {
      removeCIICPoints();

      map.flyTo({
        // These options control the ending camera position: centered at
        // the target, at zoom level 9, and north up.
        center: aUsers[0].getPosition(),
        zoom: 15,
        bearing: 10,

        // These options control the flight curve, making it move
        // slowly and zoom out almost completely before starting
        // to pan.
        speed: 0.5, // make the flying slow
        curve: 1, // change the speed at which it zooms out

        // This can be any easing function: it takes a number between
        // 0 and 1 and returns another number between 0 and 1.
        easing: function(t) {
          return t;
        }
      });
    });
    $("#Me").on('touchstart', function() {

    });


    window.hackthon.getBosses().then(d => {
      console.log(d);
      for (let boss of d) {
        aBosses.push(new BossObject(boss.id, [boss.location.x, boss.location.y], 200, boss.max_health));
      }
    }).then(() => {
      return window.hackthon.getUsers().then(d => {
        console.log(d);
        for (let player of d) {
          aUsers.push(new PlayerObject(player.id, player.group_id, [player.location.x, player.location.y]));
        }
        setInterval(() => {
          refreshUser();
        }, 1000);
      });
    }).then(() => {
      setInterval(() => {
        refreshBattle();
      }, 1000);

    });


  });
});
